{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(projects-auto-ml-pipe)=\n",
    "# Projects and automated ML pipeline\n",
    "\n",
    "This notebook demonstrates how to work with projects, source control (git), and automating the ML pipeline.\n",
    "\n",
    "Make sure you went over the basics in MLRun [**Quick Start Tutorial**](01-mlrun-basics.ipynb).\n",
    "\n",
    "MLRun Project is a container for all your work on a particular activity: all the associated code, [functions](https://docs.mlrun.org/en/stable/runtimes/functions.html), [jobs](https://docs.mlrun.org/en/stable/concepts/submitting-tasks-jobs-to-functions.html), [workflows](https://docs.mlrun.org/en/stable/concepts/workflow-overview.html), data, models, and [artifacts](https://docs.mlrun.org/en/stable/store/artifacts.html). Projects can be mapped to `git` repositories to enable versioning, collaboration, and [CI/CD](https://docs.mlrun.org/en/stable/projects/ci-integration.html).\n",
    "\n",
    "You can create project definitions using the SDK or a yaml file and store those in the MLRun DB, a file, or an archive.\n",
    "Once the project is loaded you can run jobs/workflows that refer to any project element by name, allowing separation between configuration and code. See [load projects](https://docs.mlrun.org/en/stable/projects/load-project.html) for details.\n",
    "\n",
    "Projects contain `workflows` that execute the registered functions in a sequence/graph (DAG), and that can reference project parameters, secrets and artifacts by name. MLRun currently supports three workflow engines: `local` (for simple tasks), `remote`, and [`kfp` Kubeflow Pipelines](https://www.kubeflow.org/docs/components/pipelines/overview/) (for more complex/advanced tasks). MLRun also supports a real-time workflow engine (see [online serving pipelines (graphs)](https://docs.mlrun.org/en/stable/serving/serving-graph.html). \n",
    "\n",
    "An ML Engineer can gather the different functions created by the data engineer and data scientist and create this automated pipeline.\n",
    "\n",
    "**In this tutorial**\n",
    "- [**Set up the project and functions**](#set-up-the-project-and-functions)\n",
    "- [**Work with GIT and archives**](#work-with-git-and-archives)\n",
    "- [**Build and run automated ML pipelines and CI/CD**](#build-and-run-automated-ml-pipelines-and-cicd)\n",
    "- [**Test the deployed model endpoint**](#test-the-deployed-model-endpoint)\n",
    "\n",
    "## MLRun installation and configuration\n",
    "\n",
    "Before running this notebook make sure the `mlrun` packages are installed (`pip install mlrun`) and that you have configured the access to MLRun service. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Install MLRun if not installed, run this only once (restart the notebook after the install !!!)\n",
    "%pip install mlrun"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"project\"></a>\n",
    "## Set up the project and functions\n",
    "\n",
    "**Get or create a project**\n",
    "\n",
    "There are three ways to create/load [**MLRun projects**](https://docs.mlrun.org/en/stable/projects/project.html):\n",
    "* `mlrun.projects.new_project()`  &mdash; Create a new MLRun project and optionally load it from a yaml/zip/git template.\n",
    "* `mlrun.projects.load_project()` &mdash; Load a project from a context directory or remote git/zip/tar archive.\n",
    "* `mlrun.projects.get_or_create_project()` &mdash; Load a project from the MLRun DB if it exists, or from a specified \n",
    "  context/archive. \n",
    "\n",
    "Projects refer to a `context` directory that holds all the project code and configuration. Its default value is \"./\", \n",
    "which is the directory the MLRun client runs from. \n",
    "The `context` dir is \n",
    "usually mapped to a `git` repository and/or to an IDE (PyCharm, VSCode, etc.) project.   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import mlrun\n",
    "\n",
    "project = mlrun.get_or_create_project(\n",
    "    \"tutorial\", context=\"./\", user_project=True, allow_cross_project=True\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"gs-tutorial-4-step-setting-up-project\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Register project functions\n",
    "\n",
    "To run workflows, you must save the definitions for the functions in the project so that function objects are initialized \n",
    "automatically when you load a project or when running a project version in automated CI/CD workflows. In addition, you might want to set/register other project attributes such as global parameters, secrets, and data.\n",
    "\n",
    "Functions are registered using the `set_function()` command, where you can specify the code, requirements, image, etc. \n",
    "Functions can be created from a single code/notebook file or have access to the entire project context directory. (By adding the `with_repo=True` flag, it guarantees that the project context is cloned into the function runtime environment).\n",
    "\n",
    "Function registration examples:\n",
    "\n",
    "```python\n",
    "    # Example: register a notebook file as a function\n",
    "    project.set_function('mynb.ipynb', name='test-function', image=\"mlrun/mlrun\", handler=\"run_test\")\n",
    "\n",
    "    # Define a job (batch) function that uses code/libs from the project repo\n",
    "    project.set_function(\n",
    "        name=\"myjob\", handler=\"my_module.job_handler\",\n",
    "        image=\"mlrun/mlrun\", kind=\"job\", with_repo=True,\n",
    "    )\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Function code**\n",
    "\n",
    "Run the following cell to generate the data prep file (or copy it manually):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%writefile src/data-prep.py\n",
    "\n",
    "import pandas as pd\n",
    "from sklearn.datasets import load_breast_cancer\n",
    "\n",
    "\n",
    "def breast_cancer_generator():\n",
    "    \"\"\"\n",
    "    A function that generates the breast cancer dataset\n",
    "    \"\"\"\n",
    "    breast_cancer = load_breast_cancer()\n",
    "    breast_cancer_dataset = pd.DataFrame(\n",
    "        data=breast_cancer.data, columns=breast_cancer.feature_names\n",
    "    )\n",
    "    breast_cancer_labels = pd.DataFrame(data=breast_cancer.target, columns=[\"label\"])\n",
    "    breast_cancer_dataset = pd.concat(\n",
    "        [breast_cancer_dataset, breast_cancer_labels], axis=1\n",
    "    )\n",
    "\n",
    "    return breast_cancer_dataset, \"label\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Register the function above in the project**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data_prep_func = project.set_function(\n",
    "    \"src/data-prep.py\",\n",
    "    name=\"data-prep\",\n",
    "    kind=\"job\",\n",
    "    image=\"mlrun/mlrun\",\n",
    "    handler=\"breast_cancer_generator\",\n",
    ")\n",
    "pipeline_serving_func = project.set_function(\n",
    "    func=\"\",\n",
    "    name=\"pipeline-serving\",\n",
    "    image=\"mlrun/mlrun\",\n",
    "    kind=\"serving\",\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data_prep_func.save()\n",
    "pipeline_serving_func.save()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Register additional project objects and metadata**\n",
    "\n",
    "You can define other objects (workflows, artifacts, secrets) and parameters in the project and use them in your functions, for example:\n",
    "\n",
    "```python\n",
    "    # Register a simple named artifact in the project (to be used in workflows)  \n",
    "    data_url = 'https://s3.wasabisys.com/iguazio/data/iris/iris.data.raw.csv'\n",
    "    project.set_artifact('data', target_path=data_url)\n",
    "\n",
    "    # Add a multi-stage workflow (./workflow.py) to the project with the name 'main' and save the project \n",
    "    project.set_workflow('main', \"./workflow.py\")\n",
    "    \n",
    "    # Read env vars from dict or file and set as project secrets\n",
    "    project.set_secrets({\"SECRET1\": \"value\"})\n",
    "    project.set_secrets(file_path=\"secrets.env\")\n",
    "    \n",
    "    project.spec.params = {\"x\": 5}\n",
    "```\n",
    "\n",
    "**Save the project**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "project.set_function(f\"db://{project.name}/data-prep\", name=\"data-prep\")\n",
    "project.set_function(f\"db://{project.name}/pipeline-serving\", name=\"pipeline-serving\")\n",
    "project.set_source(f\"db://{project.name}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Save the project in the db (and into the project.yaml file)\n",
    "project.save()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When you save the project it stores the project definitions in the `project.yaml`. This allows reconstructing the project in a remote cluster or a CI/CD system. \n",
    "\n",
    "See the generated project file: <a href=\"project.yaml\">**project.yaml**</a>.\n",
    "\n",
    "<a id=\"archives\"></a>\n",
    "## Work with GIT and archives\n",
    "\n",
    "### Push the project code/metadata into an archive\n",
    "\n",
    "Use standard git commands to push the current project tree into a git archive. Make sure you `.save()` the project before pushing it.\n",
    "\n",
    "    git remote add origin <server>\n",
    "    git commit -m \"Commit message\"\n",
    "    git push origin master\n",
    "\n",
    "Alternatively, you can use MLRun SDK calls:\n",
    "- `project.create_remote(git_uri, branch=branch)` &mdash; to register the remote Git path\n",
    "- `project.push()` &mdash; save the project state and commit/push updates to the remote git repo\n",
    "\n",
    "You can also save the project content and metadata into a local or remote `.zip` archive, for example: \n",
    "\n",
    "    project.export(\"../archive1.zip\")\n",
    "    project.export(\"s3://my-bucket/archive1.zip\")\n",
    "    project.export(f\"v3io://projects/{project.name}/archive1.zip\")\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id='load'></a>\n",
    "### Load a project from local/remote archive \n",
    "\n",
    "The project metadata and context (code and configuration) can be loaded and initialized using the {py:meth}`~mlrun.projects.load_project` method.\n",
    "When `url` (of the git/zip/tar) is specified, it clones a remote repo into the local `context` dir.\n",
    "\n",
    "    # Load the project and run the 'main' workflow\n",
    "    project = load_project(context=\"./\", name=\"myproj\", url=\"git://github.com/mlrun/project-archive.git\")\n",
    "    project.run(\"main\", arguments={'data': data_url})\n",
    "\n",
    "Projects can also be loaded and executed using the CLI:\n",
    "\n",
    "    mlrun project -n myproj -u \"git://github.com/mlrun/project-archive.git\" .\n",
    "    mlrun project -r main -w -a data=<data-url> ."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# load the project in the current context dir\n",
    "project = mlrun.load_project(\"./\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"pipeline\"></a>\n",
    "## Build and run automated ML pipelines and CI/CD\n",
    "\n",
    "A pipeline is created by running an MLRun **\"workflow\"**.\n",
    "The following code defines a workflow and writes it to a file in your local directory, with the file name **workflow.py**.\n",
    "The workflow describes a directed acyclic graph (DAG) which is executed using the `local`, `remote`, or `kubeflow` engines.\n",
    "\n",
    "See [running a multi-stage workflow](https://docs.mlrun.org/en/stable/concepts/workflow-overview.html).\n",
    "The defined pipeline includes the following steps:\n",
    "\n",
    "- Generate/prepare the data (`ingest`).\n",
    "- Train and the model (`train`).\n",
    "- Deploy the model as a real-time serverless function (`serving`).\n",
    "\n",
    "```{admonition} Note\n",
    "A pipeline can also include continuous build integration and deployment (CI/CD) steps, such as building container images and deploying models.\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%writefile 'src/workflow.py'\n",
    "\n",
    "from kfp import dsl\n",
    "import mlrun\n",
    "\n",
    "# Create a Kubeflow Pipelines pipeline\n",
    "@dsl.pipeline(name=\"breast-cancer-demo\")\n",
    "def pipeline(model_name=\"cancer-classifier\"):\n",
    "    # Run the ingestion function with the new image and params\n",
    "    ingest = mlrun.run_function(\n",
    "        \"data-prep\",\n",
    "        name=\"get-data\",\n",
    "        returns=[\"dataset\", \"label_column\"],\n",
    "    )\n",
    "\n",
    "    # Train a model using the auto_trainer hub function\n",
    "    train = mlrun.run_function(\n",
    "        \"hub://auto_trainer\",\n",
    "        inputs={\"dataset\": ingest.outputs[\"dataset\"]},\n",
    "        params = {\n",
    "            \"model_class\": \"sklearn.ensemble.RandomForestClassifier\",\n",
    "            \"train_test_split_size\": 0.2,\n",
    "            \"label_columns\": \"label\",\n",
    "            \"model_name\": model_name,\n",
    "        }, \n",
    "        handler='train',\n",
    "        outputs=[\"model\"],\n",
    "    )\n",
    "\n",
    "    # Deploy the trained model as a serverless function\n",
    "    mlrun.deploy_function(\n",
    "        \"pipeline-serving\",\n",
    "        models=[\n",
    "            {\n",
    "                \"key\": model_name,\n",
    "                \"model_path\": train.outputs[\"model\"],\n",
    "                \"class_name\": 'mlrun.frameworks.sklearn.SKLearnModelServer',\n",
    "            }\n",
    "        ],\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "project.set_workflow(name=\"main\", workflow_path=\"./src/workflow.py\", embed=True)\n",
    "project.save()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"gs-tutorial-4-step-register-workflow\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Run the workflow**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "> 2025-05-18 12:52:08,435 [info] Submitting remote workflow: {\"project_name\":\"tutorial-shapira\",\"schedule\":null,\"workflow_engine\":\"kfp\"}\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>Pipeline running (id=8902f0f5-b1db-4095-99b8-e86da84857fa), <a href=\"https://dashboard.default-tenant.app.cust-cs-il.iguazio-cd0.com/mlprojects/tutorial-shapira/jobs/monitor-workflows/workflow/8902f0f5-b1db-4095-99b8-e86da84857fa\" target=\"_blank\"><b>click here</b></a> to view the details in MLRun UI</div>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<!-- Generated by graphviz version 2.43.0 (0)\n",
       " -->\n",
       "<!-- Title: kfp Pages: 1 -->\n",
       "<svg width=\"8pt\" height=\"8pt\"\n",
       " viewBox=\"0.00 0.00 8.00 8.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 4)\">\n",
       "<title>kfp</title>\n",
       "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-4 4,-4 4,4 -4,4\"/>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<graphviz.graphs.Digraph at 0x7fcf5f7bba90>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "> 2025-05-18 12:52:19,173 [info] Started run workflow tutorial-shapira-main with run id = '8902f0f5-b1db-4095-99b8-e86da84857fa' by remote engine\n",
      "> 2025-05-18 12:52:19,174 [info] Waiting for pipeline run completion: {\"project\":\"tutorial-shapira\",\"run_id\":\"8902f0f5-b1db-4095-99b8-e86da84857fa\"}\n"
     ]
    },
    {
     "data": {
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<!-- Generated by graphviz version 2.43.0 (0)\n",
       " -->\n",
       "<!-- Title: kfp Pages: 1 -->\n",
       "<svg width=\"191pt\" height=\"188pt\"\n",
       " viewBox=\"0.00 0.00 191.28 188.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 184)\">\n",
       "<title>kfp</title>\n",
       "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-184 187.28,-184 187.28,4 -4,4\"/>\n",
       "<!-- breast&#45;cancer&#45;demo&#45;72v6q&#45;3152979563 -->\n",
       "<g id=\"node1\" class=\"node\">\n",
       "<title>breast&#45;cancer&#45;demo&#45;72v6q&#45;3152979563</title>\n",
       "<polygon fill=\"green\" stroke=\"black\" points=\"183.14,-36 4.14,-36 0.14,-32 0.14,0 179.14,0 183.14,-4 183.14,-36\"/>\n",
       "<polyline fill=\"none\" stroke=\"black\" points=\"179.14,-32 0.14,-32 \"/>\n",
       "<polyline fill=\"none\" stroke=\"black\" points=\"179.14,-32 179.14,0 \"/>\n",
       "<polyline fill=\"none\" stroke=\"black\" points=\"179.14,-32 183.14,-36 \"/>\n",
       "<text text-anchor=\"middle\" x=\"91.64\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">deploy&#45;pipeline&#45;serving</text>\n",
       "</g>\n",
       "<!-- breast&#45;cancer&#45;demo&#45;72v6q&#45;358856829 -->\n",
       "<g id=\"node2\" class=\"node\">\n",
       "<title>breast&#45;cancer&#45;demo&#45;72v6q&#45;358856829</title>\n",
       "<ellipse fill=\"green\" stroke=\"black\" cx=\"91.64\" cy=\"-162\" rx=\"49.29\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"91.64\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">get&#45;data</text>\n",
       "</g>\n",
       "<!-- breast&#45;cancer&#45;demo&#45;72v6q&#45;3866500718 -->\n",
       "<g id=\"node3\" class=\"node\">\n",
       "<title>breast&#45;cancer&#45;demo&#45;72v6q&#45;3866500718</title>\n",
       "<ellipse fill=\"green\" stroke=\"black\" cx=\"91.64\" cy=\"-90\" rx=\"91.78\" ry=\"18\"/>\n",
       "<text text-anchor=\"middle\" x=\"91.64\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">auto&#45;trainer&#45;train</text>\n",
       "</g>\n",
       "<!-- breast&#45;cancer&#45;demo&#45;72v6q&#45;358856829&#45;&gt;breast&#45;cancer&#45;demo&#45;72v6q&#45;3866500718 -->\n",
       "<g id=\"edge1\" class=\"edge\">\n",
       "<title>breast&#45;cancer&#45;demo&#45;72v6q&#45;358856829&#45;&gt;breast&#45;cancer&#45;demo&#45;72v6q&#45;3866500718</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M91.64,-143.7C91.64,-135.98 91.64,-126.71 91.64,-118.11\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"95.14,-118.1 91.64,-108.1 88.14,-118.1 95.14,-118.1\"/>\n",
       "</g>\n",
       "<!-- breast&#45;cancer&#45;demo&#45;72v6q&#45;3866500718&#45;&gt;breast&#45;cancer&#45;demo&#45;72v6q&#45;3152979563 -->\n",
       "<g id=\"edge2\" class=\"edge\">\n",
       "<title>breast&#45;cancer&#45;demo&#45;72v6q&#45;3866500718&#45;&gt;breast&#45;cancer&#45;demo&#45;72v6q&#45;3152979563</title>\n",
       "<path fill=\"none\" stroke=\"black\" d=\"M91.64,-71.7C91.64,-63.98 91.64,-54.71 91.64,-46.11\"/>\n",
       "<polygon fill=\"black\" stroke=\"black\" points=\"95.14,-46.1 91.64,-36.1 88.14,-46.1 95.14,-46.1\"/>\n",
       "</g>\n",
       "</g>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<graphviz.graphs.Digraph at 0x7fcf5f6a9a60>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<h2>Run Results</h2><h3>[info] Workflow 8902f0f5-b1db-4095-99b8-e86da84857fa finished, state=Succeeded</h3><br>click the hyper links below to see detailed results<br><table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th>uid</th>\n",
       "      <th>start</th>\n",
       "      <th>end</th>\n",
       "      <th>state</th>\n",
       "      <th>kind</th>\n",
       "      <th>name</th>\n",
       "      <th>parameters</th>\n",
       "      <th>results</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td><div title=\"deae3f954e2246e1a9e42e1e7868e462\"><a href=\"https://dashboard.default-tenant.app.cust-cs-il.iguazio-cd0.com/mlprojects/tutorial-shapira/jobs/monitor-jobs/auto-trainer-train/deae3f954e2246e1a9e42e1e7868e462/overview\" target=\"_blank\" >...7868e462</a></div></td>\n",
       "      <td>May 18 12:53:13</td>\n",
       "      <td>2025-05-18 12:53:18.616713+00:00</td>\n",
       "      <td>completed</td>\n",
       "      <td>run</td>\n",
       "      <td>auto-trainer-train</td>\n",
       "      <td><div class=\"dictlist\">model_class=sklearn.ensemble.RandomForestClassifier</div><div class=\"dictlist\">train_test_split_size=0.2</div><div class=\"dictlist\">label_columns=label</div><div class=\"dictlist\">model_name=cancer-classifier</div></td>\n",
       "      <td><div class=\"dictlist\">accuracy=0.956140350877193</div><div class=\"dictlist\">f1_score=0.9673202614379085</div><div class=\"dictlist\">precision_score=0.9487179487179487</div><div class=\"dictlist\">recall_score=0.9866666666666667</div></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td><div title=\"f3046e6a23ba4315851c4ae7cd614144\"><a href=\"https://dashboard.default-tenant.app.cust-cs-il.iguazio-cd0.com/mlprojects/tutorial-shapira/jobs/monitor-jobs/get-data/f3046e6a23ba4315851c4ae7cd614144/overview\" target=\"_blank\" >...cd614144</a></div></td>\n",
       "      <td>May 18 12:52:38</td>\n",
       "      <td>2025-05-18 12:52:41.216559+00:00</td>\n",
       "      <td>completed</td>\n",
       "      <td>run</td>\n",
       "      <td>get-data</td>\n",
       "      <td></td>\n",
       "      <td><div class=\"dictlist\">label_column=label</div></td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Run the workflow\n",
    "run_id = project.run(\n",
    "    \"main\",\n",
    "    arguments={\"model_name\": \"cancer-classifier\"},\n",
    "    engine=\"remote\",\n",
    "    watch=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br>\n",
    "\n",
    "**View the pipeline in MLRun UI**\n",
    "\n",
    "![workflow](./_static/images/workflow.png)\n",
    "\n",
    "<br>\n",
    "\n",
    "**Run workflows using the CLI**\n",
    "\n",
    "With MLRun you can use a single command to load the code from local dir or remote archive (Git, zip, ..) and execute a pipeline. This can be very useful for integration with CI/CD frameworks and practices. See [CI/CD integration](https://docs.mlrun.org/en/stable/projects/ci-integration.html) for more details.\n",
    "\n",
    "The following command loads the project from the current dir (`.`) and executes the workflow with an argument, for running on k8s.\n",
    "\n",
    "    mlrun project -r ./workflow.py -w -a model_name=classifier2 ."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a id=\"test-model\"></a>\n",
    "## Test the deployed model endpoint\n",
    "\n",
    "Now that your model is deployed using the pipeline, you can invoke it as usual:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "serving_fn = project.get_function(\"pipeline-serving\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'id': '68d536ee-c546-41c9-9a98-03cdc0dc78a8',\n",
       " 'model_name': 'cancer-classifier',\n",
       " 'outputs': [0],\n",
       " 'timestamp': '2025-05-18 12:56:19.804983+00:00',\n",
       " 'model_endpoint_uid': '26b8e62c2fc7434b948c23f43a4abdc3'}"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Create a mock (simulator of the real-time function)\n",
    "my_data = {\n",
    "    \"inputs\": [\n",
    "        [\n",
    "            1.371e01,\n",
    "            2.083e01,\n",
    "            9.020e01,\n",
    "            5.779e02,\n",
    "            1.189e-01,\n",
    "            1.645e-01,\n",
    "            9.366e-02,\n",
    "            5.985e-02,\n",
    "            2.196e-01,\n",
    "            7.451e-02,\n",
    "            5.835e-01,\n",
    "            1.377e00,\n",
    "            3.856e00,\n",
    "            5.096e01,\n",
    "            8.805e-03,\n",
    "            3.029e-02,\n",
    "            2.488e-02,\n",
    "            1.448e-02,\n",
    "            1.486e-02,\n",
    "            5.412e-03,\n",
    "            1.706e01,\n",
    "            2.814e01,\n",
    "            1.106e02,\n",
    "            8.970e02,\n",
    "            1.654e-01,\n",
    "            3.682e-01,\n",
    "            2.678e-01,\n",
    "            1.556e-01,\n",
    "            3.196e-01,\n",
    "            1.151e-01,\n",
    "        ]\n",
    "    ]\n",
    "}\n",
    "serving_fn.invoke(\"/v2/models/cancer-classifier/infer\", body=my_data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Done!\n",
    "\n",
    "Congratulations! You’ve completed Part 4 of the MLRun getting-started tutorial. To continue, proceed to [**Part 5 Model monitoring**](05-model-monitoring.ipynb)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "mlrun-base",
   "language": "python",
   "name": "conda-env-mlrun-base-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.22"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
